/*****************************************************************************
* | File      	:	DEV_Config.cpp
* | Author      : Waveshare team
* | Function    :
* | Info        :
*   Image scanning
*      Please use progressive scanning to generate images or fonts
*----------------
* |	This version:   V1.0
* | Date        :   2018-01-11
* | Info        :   Basic version
*
******************************************************************************/
#include "DEV_Config.h"
#include "board.h"
#include "bsp_spi.h"

#include <rtdef.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>

struct pin_context {
    const char* label; // for log print
    rt_base_t pin;
};

#define INVLIAD_PIN UINT32_MAX

struct pin_context pin_ctx_table[EPD_DEV_PIN_MAX] = {
#define PIN_MAP(label, pin) [label] = {#label, pin}
        PIN_MAP(EPD_CS_PIN, INVLIAD_PIN),
        PIN_MAP(EPD_DC_PIN, INVLIAD_PIN),
        PIN_MAP(EPD_RST_PIN, INVLIAD_PIN),
        PIN_MAP(EPD_BUSY_PIN, INVLIAD_PIN),
        PIN_MAP(RAM_CS_PIN, INVLIAD_PIN),
        PIN_MAP(SD_CS_PIN, INVLIAD_PIN),
#undef PIN_MAP
};

#define PIN_ID_NUM (sizeof(pin_ctx_table)/sizeof(pin_ctx_table[0]))

void DEV_Digital_Write(uint8_t id, uint8_t value)
{
    if (id > PIN_ID_NUM) {
        rt_kprintf("pin %d invalid!\n", id);
        return;
    }

    rt_base_t pin = pin_ctx_table[id].pin;
    if (pin == INVLIAD_PIN) {
        rt_kprintf("pin %s not set!\n", pin_ctx_table[id].label);
        return;
    }
    rt_pin_write(pin, value ? PIN_HIGH : PIN_LOW);
}

uint8_t DEV_Digital_Read(uint8_t id)
{
    if (id > PIN_ID_NUM) {
        rt_kprintf("pin %d invalid!\n", id);
        return 0xFF;
    }

    rt_base_t pin = pin_ctx_table[id].pin;
    if (pin == INVLIAD_PIN) {
        rt_kprintf("pin %s not set!\n", pin_ctx_table[id].label);
        return 0;
    }
    return rt_pin_read(pin);
}

static void GPIO_PIN_Init(uint8_t id, const char* name, rt_base_t mode)
{
    struct gpio_init gpio_init = {0};
    if (id > PIN_ID_NUM) {
        rt_kprintf("pin %d invalid!\n", id);
        return;
    }

    rt_base_t pin = rt_pin_get(name);
    if (pin < 0) {
        rt_kprintf("rt_pin_get failed, '%s' not found\n", name);
        return;
    }

    pin_ctx_table[id].pin = pin;
    rt_pin_mode(pin, mode);
}

static void DEV_PIN_Init(void)
{
    GPIO_PIN_Init(EPD_CS_PIN, "PA.1", PIN_MODE_OUTPUT); // also used to control Blue LED
    GPIO_PIN_Init(EPD_DC_PIN, "PA.5", PIN_MODE_OUTPUT); // PA.2 used by KEY1
    GPIO_PIN_Init(EPD_RST_PIN, "PA.0", PIN_MODE_OUTPUT);
    GPIO_PIN_Init(EPD_BUSY_PIN, "PA.6", PIN_MODE_INPUT);

    GPIO_PIN_Init(RAM_CS_PIN, "PE.1", PIN_MODE_OUTPUT); // also used to control Red LED
}

/******************************************************************************
function:	Initialize Arduino, Initialize Pins, and SPI
parameter:
Info:
******************************************************************************/
UBYTE DEV_Module_Init(void)
{
    DEV_PIN_Init();
    bsp_spi_init();

    EPD_CS_1;
    // SD_CS_1;
    SPIRAM_CS_1;

    return 0;
}

static int epd_dev_init()
{
    DEV_Module_Init();
    return 0;
}
INIT_DEVICE_EXPORT(epd_dev_init); // after INIT_BOARD_EXPORT

/*********************************************
function:	Hardware interface
note:
	SPI4W_Write_Byte(value) : 
		Register hardware SPI
*********************************************/	
void DEV_SPI_WriteByte(UBYTE value)
{
    bsp_spi_lock();
    bsp_spi_send(value);
    bsp_spi_unlock();
}

UBYTE DEV_SPI_ReadByte(void)
{
    UBYTE value = 0;
    bsp_spi_lock();
    value = bsp_spi_recv();
    bsp_spi_unlock();
    return value;
}

/******************************************************************************
function:	Analog microsecond delay
parameter:
Info:
******************************************************************************/
void DEV_Delay_us(UWORD xus)
{
    for(int j=xus; j > 0; j--);
}

void DEV_Module_Exit(void)
{
    DEV_Digital_Write(EPD_DC_PIN, 0);
    DEV_Digital_Write(EPD_CS_PIN, 0);

    //close 5V
    DEV_Digital_Write(EPD_RST_PIN, 0);
}
